//
//  RxTableViewSectionedAnimatedDataSource.swift
//  live
//
//  Created by melvyn on 2018/9/17.
//  Copyright © 2018 NEET. All rights reserved.
//

import UIKit
import RxSwift
import RxCocoa
import RxDataSources
import Differentiator

class RxTableViewAnimatedDataSource<S: AnimatableSectionModelType>: RxTableViewSectionedAnimatedDataSource<S> {
    
    var performBatchUpdates: PublishSubject<[IndexPath]> = PublishSubject()

    var dataSet = false
    
    open override func tableView(_ tableView: UITableView, observedEvent: Event<Element>) {
        Binder(self) { dataSource, newSections in

            if !self.dataSet {
                self.dataSet = true
                dataSource.setSections(newSections)
                tableView.reloadData()
                
                self.performBatchUpdates.onNext(self.indexes(newSections))
            }
            else {
                DispatchQueue.main.async {
                    // if view is not in view hierarchy, performing batch updates will crash the app
                    if tableView.window == nil {
                        dataSource.setSections(newSections)
                        tableView.reloadData()
                        self.performBatchUpdates.onNext(self.indexes(newSections))
                        return
                    }
                    let oldSections = dataSource.sectionModels
                    do {
                        let differences = try Diff.differencesForSectionedView(initialSections: oldSections, finalSections: newSections)
                        
                        switch self.decideViewTransition(self, tableView, differences) {
                        case .animated:
                            for difference in differences {
                                dataSource.setSections(difference.finalSections)
                                
                                tableView.performBatchUpdates(difference, animationConfiguration: self.animationConfiguration)
                                let indexs = difference.insertedItems.map { IndexPath(item: $0.itemIndex, section: $0.sectionIndex) }
                                self.performBatchUpdates.onNext(indexs)
                            }
                        case .reload:
                            self.setSections(newSections)
                            tableView.reloadData()
                            self.performBatchUpdates.onNext(self.indexes(newSections))
                            return
                        }
                    }
                    catch _ {
                        self.setSections(newSections)
                        tableView.reloadData()
                        self.performBatchUpdates.onNext(self.indexes(newSections))
                    }
                }
            }
            }.on(observedEvent)
    }
    
    private func indexes(_ sections: [S]) -> [IndexPath] {
        guard !sections.isEmpty else {
            return []
        }
        guard !sections.last!.items.isEmpty else {
            return []
        }
        let section = sections.count - 1
        let row = sections.last!.items.count - 1
        return [IndexPath.init(row: row, section: section)]
    }
}
